package top.malaoshi.webmvc;


import org.objectweb.asm.*;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
 * 解析方法参数名称
 */

public class MethodArgumentNameResolver2 {

    /**
     * 获取方法的参数名称
     * @param method
     * @return
     */
    public static String[] handle(Method method) throws IOException {

        final String methodName = method.getName();
        final Class<?>[] methodParameterTypes = method.getParameterTypes();
        final int methodParameterCount = methodParameterTypes.length;
        final String className = method.getDeclaringClass().getName();
        final boolean isStatic = Modifier.isStatic(method.getModifiers());
        final String[] methodParametersNames = new String[methodParameterCount];

        // 只能用这种方式才能读取 .class 文件，然后将inputstream传给 ClassReader
        String classPath = "/"+className.replace('.', '/') + ".class";
        InputStream is = MethodArgumentNameResolver2.class.getResourceAsStream(classPath);

        ClassReader cr = new ClassReader(is);
        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
//        ClassAdapter classAdapter = new ClassAdapter(cw) {
//            public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
//
//                MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
//
//                final Type[] argTypes = Type.getArgumentTypes(desc);
//
//                //参数类型不一致
//                if (!methodName.equals(name) || !matchTypes(argTypes, methodParameterTypes)) {
//                    return mv;
//                }
//                return new MethodAdapter(mv) {
//                    public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
//                        //如果是静态方法，第一个参数就是方法参数，非静态方法，则第一个参数是 this ,然后才是方法的参数
//                        int methodParameterIndex = isStatic ? index : index - 1;
//                        if (0 <= methodParameterIndex && methodParameterIndex < methodParameterCount) {
//                            methodParametersNames[methodParameterIndex] = name;
//                        }
//                        super.visitLocalVariable(name, desc, signature, start, end, index);
//                    }
//                };
//            }
//        };
        ClassVisitor classAdapter = new ClassVisitor(Opcodes.ASM7) {
            public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {

                MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);

                final Type[] argTypes = Type.getArgumentTypes(desc);

                //参数类型不一致
                if (!methodName.equals(name) || !matchTypes(argTypes, methodParameterTypes)) {
                    return mv;
                }
                return new MethodVisitor(Opcodes.ASM7) {
                    public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
                        //如果是静态方法，第一个参数就是方法参数，非静态方法，则第一个参数是 this ,然后才是方法的参数
                        int methodParameterIndex = isStatic ? index : index - 1;
                        if (0 <= methodParameterIndex && methodParameterIndex < methodParameterCount) {
                            methodParametersNames[methodParameterIndex] = name;
                        }
                        super.visitLocalVariable(name, desc, signature, start, end, index);
                    }
                };
            }
        };
        cr.accept(classAdapter, 0);
        return methodParametersNames;
    }

    /**
     * 比较参数是否一致
     */
    private static boolean matchTypes(Type[] types, Class<?>[] parameterTypes) {
        if (types.length != parameterTypes.length) {
            return false;
        }
        for (int i = 0; i < types.length; i++) {
            if (!Type.getType(parameterTypes[i]).equals(types[i])) {
                return false;
            }
        }
        return true;
    }


}
